//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_issue_api_serv

import (
	"context"
	"fmt"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/bg_runner/tasks"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/alarm_dao"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_project"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_alarm_api"
	"google.golang.org/protobuf/proto"
)

func (apiImpl *ProjectIssueApiImpl) adjustDelayCheckTask(projectId, issueId string, issueState int32, hasDeadLineTime bool, deadLineTime int64) error {
	cfgItem, err := alarm_dao.ConfigDao.Get(context.Background(), projectId)
	if err != nil {
		return nil //配置不存在
	}

	defer func() {
		go api_common.SendNoticeToProjectScope(context.Background(), projectId, &notices_project.UpdateAlarmStatNotice{
			ProjectId: projectId,
		})
	}()

	nowTime := time.Now().UnixNano() / 1e6

	hitTaskId := fmt.Sprintf("%s:%d", issueId, uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DELAY_HIT))
	err = dao.BgTaskDao.RemoveTask(context.Background(), hitTaskId)
	if err != nil {
		return err
	}
	err = alarm_dao.AlarmDao.Remove(context.Background(), projectId, hitTaskId) //任务ID和告警ID相同
	if err != nil {
		return err
	}
	if cfgItem.EnableIssueDelayCheck && hasDeadLineTime {
		err = dao.BgTaskDao.Insert(context.Background(), hitTaskId, nowTime, deadLineTime+int64(cfgItem.IssueDelayHitValue)*24*3600*1000, &tasks.IssueDelayCheck{
			ProjectId: projectId,
			IssueId:   issueId,
			AlarmType: uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DELAY_HIT),
		})
		if err != nil {
			return err
		}
	}

	alertTaskId := fmt.Sprintf("%s:%d", issueId, uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DELAY_ALERT))
	err = dao.BgTaskDao.RemoveTask(context.Background(), alertTaskId)
	if err != nil {
		return err
	}
	err = alarm_dao.AlarmDao.Remove(context.Background(), projectId, alertTaskId) //任务ID和告警ID相同
	if err != nil {
		return err
	}
	if cfgItem.EnableIssueDelayCheck && hasDeadLineTime {
		err = dao.BgTaskDao.Insert(context.Background(), alertTaskId, nowTime, deadLineTime+int64(cfgItem.IssueDelayAlertValue)*24*3600*1000, &tasks.IssueDelayCheck{
			ProjectId: projectId,
			IssueId:   issueId,
			AlarmType: uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DELAY_ALERT),
		})
		if err != nil {
			return err
		}
	}

	return nil
}

func (apiImpl *ProjectIssueApiImpl) checkReOpen(projectId, issueId string, issueType, reOpenCount uint32) error {
	cfgItem, err := alarm_dao.ConfigDao.Get(context.Background(), projectId)
	if err != nil {
		return nil //配置不存在
	}

	defer func() {
		go api_common.SendNoticeToProjectScope(context.Background(), projectId, &notices_project.UpdateAlarmStatNotice{
			ProjectId: projectId,
		})
	}()

	nowTime := time.Now().UnixNano() / 1e6

	hitAlarmId := fmt.Sprintf("%s:%d", issueId, uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_HIT))
	err = alarm_dao.AlarmDao.Remove(context.Background(), projectId, hitAlarmId)
	if err != nil {
		return err
	}

	alertAlarmId := fmt.Sprintf("%s:%d", issueId, uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_ALERT))
	alarm_dao.AlarmDao.Remove(context.Background(), projectId, alertAlarmId)
	if err != nil {
		return err
	}

	if cfgItem.EnableIssueReOpenCheck && reOpenCount >= cfgItem.IssueReOpenAlertValue {
		alarmType := project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_ALERT
		alarm := &project_alarm_api.Alarm{
			AlarmId:   alertAlarmId,
			ProjectId: projectId,
			TimeStamp: nowTime,
			AlarmType: alarmType,
			Title:     "",
			Content: &project_alarm_api.Alarm_IssueReOpenAlertInfo{
				IssueReOpenAlertInfo: &project_alarm_api.IssueReOpenAlertInfo{
					IssueId:   issueId,
					IssueType: issueType,
				},
			},
		}
		content, err := proto.Marshal(alarm)
		if err != nil {
			return err
		}
		return alarm_dao.AlarmDao.Insert(context.Background(), &alarm_dao.AlarmDbItem{
			AlarmId:    alertAlarmId,
			ProjectId:  projectId,
			TimeStamp:  nowTime,
			AlarmType:  uint32(alarmType),
			AlarmLevel: alarm_dao.ALARM_LEVEL_ALERT,
			Content:    content,
		})
	} else if cfgItem.EnableIssueReOpenCheck && reOpenCount >= cfgItem.IssueReOpenHitValue {
		alarmType := project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_HIT
		alarm := &project_alarm_api.Alarm{
			AlarmId:   alertAlarmId,
			ProjectId: projectId,
			TimeStamp: nowTime,
			AlarmType: alarmType,
			Title:     "",
			Content: &project_alarm_api.Alarm_IssueReOpenHitInfo{
				IssueReOpenHitInfo: &project_alarm_api.IssueReOpenHitInfo{
					IssueId:   issueId,
					IssueType: issueType,
				},
			},
		}
		content, err := proto.Marshal(alarm)
		if err != nil {
			return err
		}
		return alarm_dao.AlarmDao.Insert(context.Background(), &alarm_dao.AlarmDbItem{
			AlarmId:    alertAlarmId,
			ProjectId:  projectId,
			TimeStamp:  nowTime,
			AlarmType:  uint32(alarmType),
			AlarmLevel: alarm_dao.ALARM_LEVEL_HIT,
			Content:    content,
		})
	}
	return nil
}

func (apiImpl *ProjectIssueApiImpl) checkDependMe(projectId, issueId string, issueType, dependMeCount uint32) error {
	cfgItem, err := alarm_dao.ConfigDao.Get(context.Background(), projectId)
	if err != nil {
		return nil //配置不存在
	}

	defer func() {
		go api_common.SendNoticeToProjectScope(context.Background(), projectId, &notices_project.UpdateAlarmStatNotice{
			ProjectId: projectId,
		})
	}()

	nowTime := time.Now().UnixNano() / 1e6

	hitAlarmId := fmt.Sprintf("%s:%d", issueId, uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DEPEND_HIT))
	err = alarm_dao.AlarmDao.Remove(context.Background(), projectId, hitAlarmId)
	if err != nil {
		return err
	}

	alertAlarmId := fmt.Sprintf("%s:%d", issueId, uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DEPEND_ALERT))
	alarm_dao.AlarmDao.Remove(context.Background(), projectId, alertAlarmId)
	if err != nil {
		return err
	}

	if cfgItem.EnableIssueDependCheck && dependMeCount >= cfgItem.IssueDependAlertValue {
		alarmType := project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DEPEND_ALERT
		alarm := &project_alarm_api.Alarm{
			AlarmId:   alertAlarmId,
			ProjectId: projectId,
			TimeStamp: nowTime,
			AlarmType: alarmType,
			Title:     "",
			Content: &project_alarm_api.Alarm_IssueDependAlertInfo{
				IssueDependAlertInfo: &project_alarm_api.IssueDependAlertInfo{
					IssueId:   issueId,
					IssueType: issueType,
				},
			},
		}
		content, err := proto.Marshal(alarm)
		if err != nil {
			return err
		}
		return alarm_dao.AlarmDao.Insert(context.Background(), &alarm_dao.AlarmDbItem{
			AlarmId:    alertAlarmId,
			ProjectId:  projectId,
			TimeStamp:  nowTime,
			AlarmType:  uint32(alarmType),
			AlarmLevel: alarm_dao.ALARM_LEVEL_ALERT,
			Content:    content,
		})
	} else if cfgItem.EnableIssueDependCheck && dependMeCount >= cfgItem.IssueDependHitValue {
		alarmType := project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DEPEND_HIT
		alarm := &project_alarm_api.Alarm{
			AlarmId:   alertAlarmId,
			ProjectId: projectId,
			TimeStamp: nowTime,
			AlarmType: alarmType,
			Title:     "",
			Content: &project_alarm_api.Alarm_IssueDependHitInfo{
				IssueDependHitInfo: &project_alarm_api.IssueDependHitInfo{
					IssueId:   issueId,
					IssueType: issueType,
				},
			},
		}
		content, err := proto.Marshal(alarm)
		if err != nil {
			return err
		}
		return alarm_dao.AlarmDao.Insert(context.Background(), &alarm_dao.AlarmDbItem{
			AlarmId:    alertAlarmId,
			ProjectId:  projectId,
			TimeStamp:  nowTime,
			AlarmType:  uint32(alarmType),
			AlarmLevel: alarm_dao.ALARM_LEVEL_HIT,
			Content:    content,
		})
	}
	return nil
}
